package com.evendai.sipdemo.sip.helper

import android.os.Handler
import android.os.Looper
import android.os.Message
import com.evendai.loglibrary.Timber
import com.evendai.sipdemo.App
import com.evendai.sipdemo.Constants
import com.evendai.sipdemo.EventBusEventType
import com.evendai.sipdemo.PersistentVariables
import org.doubango.ngn.NgnEngine
import org.doubango.ngn.events.NgnRegistrationEventTypes
import org.doubango.ngn.media.NgnCameraProducer
import org.doubango.ngn.media.NgnProxyAudioProducer
import org.doubango.ngn.media.NgnProxyVideoProducer
import org.doubango.ngn.sip.NgnSipSession
import org.doubango.ngn.utils.NgnConfigurationEntry
import org.doubango.tinyWRAP.MediaSessionMgr
import org.doubango.tinyWRAP.tmedia_pref_video_size_t
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlin.concurrent.thread

/** sip注册帮助类，以简化sip的注册过程 */
object SipRegisterHelper {

    private var callback: ((Boolean, String?) -> Unit?)? = null
    private var registrationStartTime = 0L
    private var timeOutHandler: Handler? = null

    fun register(callback: (Boolean, String?) -> Unit?) {
        EngineHelper.startEngine() { engineStartSuccess ->
            if (engineStartSuccess) {
                startRegisterSip(callback)
            } else {
                callback(false, "Engine启动失败")
            }
        }
    }

    private fun startRegisterSip(callback: (Boolean, String?) -> Unit?) {
        Timber.fi("开始注册sip")
        init()

        val sipService = NgnEngine.getInstance().sipService

        if (sipService.isRegistered) {
            Timber.fi("注册Sip时发现Sip已经注册")
            callback(true, null)
            return
        }

        if (sipService.registrationState == NgnSipSession.ConnectionState.CONNECTED || sipService.registrationState == NgnSipSession.ConnectionState.TERMINATING) {
            Timber.fw("注册Sip时，sipService.registrationState = ${sipService.registrationState}")
            sipService.stopStack()
        }

        // 能走到这个位置再赋值给成员变量，在receiveRegisterState()方法中需要用到，而且到时需要手动释放这些成员变量
        SipRegisterHelper.callback = callback

        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this)
        }

        registrationStartTime = System.currentTimeMillis()
        if (timeOutHandler == null) {
            timeOutHandler = Handler(Looper.getMainLooper())
        }
        timeOutHandler?.removeCallbacksAndMessages(null)
        timeOutHandler?.postDelayed({
            // 30秒后检查是否注册上了，如果没有注册上就算超时。因为有时注册半小时都不返回注册结果的，所以要主动查询注册状态
            if (!sipService.isRegistered) {
                Timber.fw("注册超时，超过30秒了还没注册上")
                registrationFail("sip注册超时")
            } else {
                Timber.fw("postDelay这里竟然收到了注册成功，见鬼了！！")
            }
        }, 30_000L)

        // 网络不好的话，这个注册会阻塞很久的，所以要开子线程
        thread {
            val registerSuccess = sipService.register(App.getContext())
            Timber.fi("开始注册，sipService.register() = $registerSuccess")
            if (!registerSuccess) {
                Timber.fw("Sip注册失败，sipService.register(context)函数返回false")
                registrationFail()
            }
        }
    }

    @Suppress("unused")
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun receiveRegisterState(message: Message) {
        if (message.what != EventBusEventType.REGISTER_STATE) {
            return
        }

        when (message.obj as NgnRegistrationEventTypes) {
            NgnRegistrationEventTypes.REGISTRATION_OK -> {      // 注册成功
                Timber.fi("Sip注册成功")
                timeOutHandler?.removeCallbacksAndMessages(null)
                timeOutHandler = null
                callback?.invoke(true, null)
                release()
            }
            NgnRegistrationEventTypes.UNREGISTRATION_OK -> {    // 注册失败，解除注册也是走这里
                Timber.fw("Sip注册失败")
                registrationFail()
            }
            else -> { }
        }
    }

    /** 注册失败 */
    private fun registrationFail(failMsg: String? = null) {
        Timber.fw("注册失败函数被调用，失败原因：$failMsg")
        timeOutHandler?.removeCallbacksAndMessages(null)
        timeOutHandler = null
        EngineHelper.stopEngine {
            callback?.invoke(false, failMsg ?: "sip注册失败")
            release()
        }
    }

    /** Sip登录前的初始化设置 */
    private fun init() {
        val config = NgnEngine.getInstance().configurationService
        val sipAccount = PersistentVariables.sipAccount
        val sipIp = PersistentVariables.sipIp
        val sipPort = PersistentVariables.sipPort
        val transport = PersistentVariables.transport
        val identityIMPU = "sip:$sipAccount@$sipIp"
        val password = PersistentVariables.sipPassword
        val videoSize = config.getString(NgnConfigurationEntry.QOS_PREF_VIDEO_SIZE, NgnConfigurationEntry.DEFAULT_QOS_PREF_VIDEO_SIZE)
        val displayName = if (PersistentVariables.displayName.isBlank()) sipAccount else PersistentVariables.displayName

        Timber.i("sipAccount=$sipAccount, password = $password, identityIMPU=$identityIMPU")
        Timber.i("sipIp=$sipIp, port = $$sipPort, transport = $transport，videoSize = $videoSize")

        config.apply {
            putString(NgnConfigurationEntry.NETWORK_PCSCF_HOST, sipIp)          // 设置sip服务器ip
            putInt(NgnConfigurationEntry.NETWORK_PCSCF_PORT, sipPort)           // 设置sip服务器端口
            putString(NgnConfigurationEntry.NETWORK_TRANSPORT, transport)       // 设置传输方式
            putString(NgnConfigurationEntry.IDENTITY_DISPLAY_NAME, displayName) // 设置显示名称
            putString(NgnConfigurationEntry.IDENTITY_IMPU, identityIMPU)        // 设置Public Identity
            putString(NgnConfigurationEntry.IDENTITY_IMPI, sipAccount)          // 设置Private Identity
            putString(NgnConfigurationEntry.IDENTITY_PASSWORD, password)        // 设置密码
            putString(NgnConfigurationEntry.NETWORK_REALM, sipIp)               // 设置realm
            putBoolean(NgnConfigurationEntry.NETWORK_USE_WIFI, true)      // 允许使用Wifi
            putBoolean(NgnConfigurationEntry.NETWORK_USE_3G, true)        // 允许使用蜂窝网络
//            putString(NgnConfigurationEntry.QOS_PREF_VIDEO_SIZE, videoSize.toString()) // 设置分辨率
            putBoolean(NgnConfigurationEntry.GENERAL_FULL_SCREEN_VIDEO, true) // 设置全屏拉伸显示
            commit()
        }

//        MediaSessionMgr.defaultsSetPrefVideoSize(videoSize) // 设置视频大小
        //NgnCameraProducer.useFrontFacingCamera()   // 设置使用前置摄像头
        NgnCameraProducer.useRearCamera()            // 设置使用后置摄像头
        Constants.sSpeakerphoneOn = true             // 设置扬声器开关
        NgnProxyAudioProducer.sOnMute = false        // 设置静音开关，注，只是禁止自己说话，还是可以听到别人说话的
        NgnProxyVideoProducer.isAudioMeeting = false // 设置是否是语音会议，如果是，则只有声音没有画面
    }

    private fun release() {
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this)
        }
        callback = null
    }

}